package assignment04;

import gnu.trove.iterator.TIntDoubleIterator;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.map.TIntDoubleMap;
import gnu.trove.map.hash.TIntDoubleHashMap;
import gnu.trove.set.TIntSet;

public class IntCounter {

	TIntDoubleMap entries;

	int currentModCount = 0;
	int cacheModCount = -1;
	double cacheTotalCount = 0.0;

	public TIntSet keySet() {
		return entries.keySet();
	}

	public int size() {
		return entries.size();
	}

	public boolean isEmpty() {
		return size() == 0;
	}

	public boolean containsKey(int key) {
		return entries.containsKey(key);
	}

	public double removeKey(int key) {
		double d = entries.remove(key);
		return d;
	}

	public double getCount(int key) {
		double value = entries.get(key);
		return value;
	}

	public void setCount(int key, double count) {
		currentModCount++;
		entries.put(key, count);
	}

	public void incrementCount(int key, double increment) {
		setCount(key, getCount(key) + increment);
	}

	public void elementwiseMax(IntCounter counter) {
		int key;
		for (TIntIterator it = counter.keySet().iterator(); it.hasNext();) {
			key = it.next();
			double count = counter.getCount(key);
			if (getCount(key) < count) {
				setCount(key, count);
			}
		}
	}

	public double totalCount() {
		if (currentModCount != cacheModCount) {
			double total = 0.0;
			for (double value : entries.values()) {
				total += value;
			}
			cacheTotalCount = total;
			cacheModCount = currentModCount;
		}
		return cacheTotalCount;
	}

	public void normalize() {
		double totalCount = totalCount();
		int key;
		for (TIntIterator it = keySet().iterator(); it.hasNext();) {
			key = it.next();
			setCount(key, getCount(key) / totalCount);
		}
	}
	
	public void reset() {
		for (TIntIterator it = keySet().iterator(); it.hasNext();) {
			int key = it.next();
			setCount(key, 0.0);
		}
	}

	public int argMax() {
		double maxCount = Double.NEGATIVE_INFINITY;
		int maxKey = 0;
		for (TIntDoubleIterator it = entries.iterator(); it.hasNext();) {
			it.advance();
			if (it.value() > maxCount || maxKey == 0) {
				maxKey = it.key();
				maxCount = it.value();
			}
		}
		return maxKey;
	}

	public IntCounter() {
		entries = new TIntDoubleHashMap();
	}
}
